pub mod complie;

use std::env;
use std::fs;
use std::io::{self};
// use std::path::Path;
use crate::complie::*;
// use generate_ast::ast;

fn main() {
    // 执行程序
    exec_qi();

    // test_ast();
}

fn test_ast() {
    let left = Expr::Unary {
        operator: Token::of(TokenType::Minus, "-".to_string()),
        right: Box::new(Expr::Literal { value: LiteralType::NUMBER("123".to_string()) })
    };

    let right = Expr::Grouping {
        expression: Box::new(Expr::Literal { value: LiteralType::NUMBER("45.67".to_string()) })
    };

    let x = Expr::Binary {
        left: Box::new(left),
        operator: Token::of(TokenType::Star, "*".to_string()),
        right: Box::new(right)
    };

    println!("{}", x.accept());
}


fn exec_qi() {
    // 1、接受命令行参数
    let args: Vec<String> = env::args().collect();
    // 参数：0 -> 执行文件名称  1 -> 参数1
    // println!("{}", args.join(","));

    let content = match &args[..] {
        // 交互性解释器
        [_]                      => run_repl(),
        // 编译.qi文件 运行时如：cargo run resources\hello.qi
        [_, file_path]   => run_file(&file_path),
        // 退出
        _                        => panic!("{}", "命令行参数不对"),
    };

    let _ = run(content);
}


/**
 * 文件编译
 */
fn run_file(file_path: &String) -> Vec<String> {
    if file_path.ends_with(".qi") {
        run_file_read(file_path)
    } else {
        panic!("{}", "必须为.qi文件类型");
        // std::process::exit(exitcode::DATAERR);
    }
}

/**
 * 交互行解释器
 */
fn run_repl() -> Vec<String> {
    let stdin = io::stdin();
    stdin.lines().into_iter().map(
        |line| {
            match line {
                Ok(l)   => l,
                Err(_)  => panic!("交互输入出现问题"),
            }
        }
    ).collect()
}

/**
 * 文件读取
 */
fn run_file_read(file_path: &String) -> Vec<String> {
    // 要不要move都可以，反正先写着。总感觉写了性能好一些
    match fs::read_to_string(file_path) {
        Ok(data)    => data.lines().into_iter().map(move |c| c.to_string()).collect(),
        Err(e)       => panic!("文件读取错误:{}", e),
    }
}

fn run(content: Vec<String>) -> Result<String, String> {
    let tokens = content.iter().map(|line| {Scanner{tokens: vec![], source: line.chars().collect(), current: 0}}).map(|mut x| x.scan_tokens());
    tokens.for_each(|xx| {println!("{:?}", xx)});
    Ok("good".to_string())
}